//Copyright 2010 Balazs Keri, Imre Keri
//
//This file is part of FireworksCreator.
//
//FireworksCreator is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//FireworksCreator is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with FireworksCreator.  If not, see <http://www.gnu.org/licenses/>.
//
#ifndef _IDENTIFIED_H
#define _IDENTIFIED_H
//
#include <global.h>
#include "id.h"
#include "iddictionary.h"
#include "restorestream.h"
#include "restoreerror.h"
//
class Identified;
QDataStream &operator<<(QDataStream &p_stream,const Identified *p_ptr);
RestoreStream &operator>>(RestoreStream &p_stream,Identified *&p_ptr);
//
class Identified
:
public QObject
{
   Q_OBJECT
   Q_DISABLE_COPY(Identified)
public:
   template<class T> static RestoreStream &restore_object(RestoreStream &p_stream,T *&p_object)
   {
      Identified *ptr;p_stream>>ptr;
      p_object=qobject_cast<T*>(ptr);
      if(ptr&&!p_object)
         throw(RestoreError("wrong type of object"));
      return p_stream;
   }
public:
   Identified(QObject *p_parent=0);
   Id get_id()const;
   void set_id(Id p_id);
/*//
   bool is_particle_template() const;
   bool is_emitter_template() const;
   bool is_shooter() const;*/
private:
   Id id;
};
//
/*template<Identified*> QDataStream &operator<<(QDataStream &p_stream,const QList<Identified*> &p_list)
{
   p_stream<<static_cast<quint32>(p_list.count());
   for(int i=0;i<p_list.count();++i)
      p_stream<<(p_list.at(i));
   return p_stream;
}
template<typename KEY,typename VALUE> QDataStream &operator<<(QDataStream &p_stream,const QHash<KEY,VALUE> &p_hash)
{
   typedef QHash<KEY,VALUE> Hash;
   p_stream<<static_cast<quint32>(p_hash.count());
   for(typename Hash::ConstIterator i=p_hash.begin();i!=p_hash.end();++i)
   {
      p_stream<<i.key();
      p_stream<<i.value();
   }
   return p_stream;
}
template<typename KEY,Identified*> QDataStream &operator<<(QDataStream &p_stream,const QHash<KEY,Identified*> &p_hash)
{
   typedef QHash<KEY,Identified*> Hash;
   p_stream<<static_cast<quint32>(p_hash.count());
   for(typename Hash::ConstIterator i=p_hash.begin();i!=p_hash.end();++i)
   {
      p_stream<<i.key();
      p_stream<<i.value();
   }
   return p_stream;
}*/
//
/*RestoreStream &operator>>(RestoreStream &p_stream,QList<Identified*> &p_list)throw(RestoreError)
{
   try
   {
      quint32 count;p_stream>>count;
      p_list.clear();
      for(quint32 i=0;i<count;++i)
      {
         Identified *obj;p_stream>>obj;
         p_list.append(obj);
      }
   }
   catch(...)
   {
      p_list.clear();
      throw;
   }
   return p_stream;
}
template<typename KEY,typename VALUE> RestoreStream &operator>>(RestoreStream &p_stream,QHash<KEY,VALUE> &p_hash)throw(RestoreError)
{
   try
   {
      quint32 count;p_stream>>count;
      p_hash.clear();
      for(quint32 i=0;i<count;++i)
      {
         KEY key;
         VALUE value;
         p_stream>>key>>value;
         p_hash.insert(key,value);
      }
   }
   catch(...)
   {
      p_hash.clear();
      throw;
   }
   return p_stream;
}
template<typename KEY,Identified*> RestoreStream &operator>>(RestoreStream &p_stream,QHash<KEY,Identified*> &p_hash)throw(RestoreError)
{
   try
   {
      quint32 count;p_stream>>count;
      p_hash.clear();
      for(quint32 i=0;i<count;++i)
      {
         KEY key;
         Identified *value;
         p_stream>>key>>value;
         p_hash.insert(key,value);
      }
   }
   catch(...)
   {
      p_hash.clear();
      throw;
   }
   return p_stream;
}*/
//
// copy of Qt operators for QDataStream, changed to RestoreStream and added exception support
template <typename T>
RestoreStream& operator>>(RestoreStream& s, QList<T>& l)
{
    l.clear();
    quint32 c;
    s >> c;
    for(quint32 i = 0; i < c; ++i)
    {
        T t;
        s >> t;
        l.append(t);
        if (s.atEnd())
            throw(RestoreError("unexpected end of stream"));
    }
    return s;
}
template <typename T>
RestoreStream& operator>>(RestoreStream& s, QLinkedList<T>& l)
{
    l.clear();
    quint32 c;
    s >> c;
    for(quint32 i = 0; i < c; ++i)
    {
        T t;
        s >> t;
        l.append(t);
        if (s.atEnd())
           throw(RestoreError("unexpected end of stream"));
    }
    return s;
}
template<typename T>
RestoreStream& operator>>(RestoreStream& s, QVector<T>& v)
{
    v.clear();
    quint32 c;
    s >> c;
    v.resize(c);
    for(quint32 i = 0; i < c; ++i) {
        T t;
        s >> t;
        v[i] = t;
    }
    return s;
}
template <typename T>
RestoreStream &operator>>(RestoreStream &in, QSet<T> &set)
{
    set.clear();
    quint32 c;
    in >> c;
    for (quint32 i = 0; i < c; ++i) {
        T t;
        in >> t;
        set << t;
        if (in.atEnd())
           throw(RestoreError("unexpected end of stream"));
    }
    return in;
}
template <class Key, class T>
Q_OUTOFLINE_TEMPLATE RestoreStream &operator>>(RestoreStream &in, QHash<Key, T> &hash)
{
    RestoreStream::Status oldStatus = in.status();
    in.resetStatus();
    hash.clear();

    quint32 n;
    in >> n;

    try
    {
        for (quint32 i = 0; i < n; ++i) {
            if (in.status() != RestoreStream::Ok)
                throw(RestoreError("bad stream status"));

            Key k;
            T t;
            in >> k;
            in >> t;
            hash.insertMulti(k, t);
        }
        if (in.status() != RestoreStream::Ok)
            throw(RestoreError("bad stream status"));
    }
    catch(RestoreError)
    {
       hash.clear();
       if (oldStatus != RestoreStream::Ok)
           in.setStatus(oldStatus);
       throw;
    }
    if (oldStatus != RestoreStream::Ok)
        in.setStatus(oldStatus);
    return in;
}
//
#endif
